/******************************************************************************
 * Copyright (c) KylinSoft  Co., Ltd. 2021. All rights reserved.
 * lcr licensed under the Mulan PSL v2.

 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 * Author: xiapin
 * Create: 2021-12-24
 * Description: obmep types define.
 ******************************************************************************/
#ifndef _OBMP_TYPE_H_
#define _OBMP_TYPE_H_

#include <stddef.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdint.h>
#include "list.h"

typedef unsigned char           U8;
typedef unsigned short          U16;
typedef signed   short          S16;
typedef unsigned int            U32;
typedef signed int              S32;
typedef unsigned long           U64;
typedef unsigned int            BIT_DEF;

#define OBMP_DEBUG
#define SUPPORT_THREAD_MAX      ((sysconf(_SC_NPROCESSORS_CONF)) * 4)
/* Default slice size is 8, so the max unit memory size is 8*MAX_BLOCK_COUNT bytes */
#define MAX_BLOCK_COUNT         (sizeof(void *) * 8) /* 64bit -> 512bit bytes */
/* Each thread cache buffer size, should be aligned to PAGESIZE. default 1M */
#define PER_CACHE_SIZE          (768 * 1024)

#define MAIN_AREA_SIZE          (PER_CACHE_SIZE)

#define __ALIGN_MASK(x, mask)   (((x) + (mask)) & ~(mask))
#define __ALIGN_MP(x, a)        __ALIGN_MASK(x, (a) - 1)

#define ALIGN(x, a)             __ALIGN_MP((x), (a))

#define SLICE_SIZE              (8)
#define SLICE_SHIFT             (3)

#define MMAP_THRES_HOLD         (65536)
#define SLICE_HIGH              (4096)
#define SLICE_HIGH_SHIFT        (12)
#define SLICE_HIGH_THRES        (1024)

#define SLICE_MID               (64)
#define SLICE_MID_SHIFT         (6)
#define SLICE_MID_THRES         (256)

#define SLICE_LOW               (8)
#define SLICE_LOW_SHIFT         (3)
#define SLICE_MASK(s)           ((s) - 1)

typedef struct st_mem_pool              mem_pool_t;
typedef struct st_mem_block_info        mem_block_info_t;
typedef struct st_thread_cache          thread_cache_t;

#define ptr_to_mem_unit(ptr) \
    (mem_unit_t *)(((uintptr_t)ptr) - sizeof(mem_unit_t))
#define mem_unit_to_ptr(unit_ptr) \
    (void *)(((uintptr_t)unit_ptr) + sizeof(mem_unit_t))

#define MU_CHECK_VALUE(mu) (~(mu)->info.unit_size & 0xffff)
#define MU_IS_FROM_OBMP(mu) ((MU_CHECK_VALUE(mu) == (mu)->check))

#if !defined(likely) && defined(__GNUC__)
    #define likely(x)      __builtin_expect(!!(x), 1)
    #define unlikely(x)    __builtin_expect(!!(x), 0)
#else
    #define likely(x)       (x)
    #define unlikely(x)     (x)
#endif

#ifndef MP_ASSERT
// # define MP_ASSERT(x)   if (!(x)) {abort();}
# define MP_ASSERT(x)
#endif

#define OBMP_UNUSED_VAR(x)      (void)(x)
#define OBMP_UNUSED_FUNC        __attribute__((__unused__))

// TODO: replace bit field
typedef union {
    struct {
        BIT_DEF     is_free            : 1;
        BIT_DEF     belongs            : 1;
        BIT_DEF     unit_size          : 30; /* Max support bytes small unit size */
    };
    U32             value;
} mem_unit_info_u;

typedef struct st_mem_unit {
    mem_unit_info_u info;
    U32             check;
    void            *next;
} mem_unit_t __attribute__((aligned(sizeof(void *))));

struct st_mem_block_info {
    mem_unit_t      *free_list;
    U64             alloced;
};

struct st_chunk {
    void            *buffer;
    U32             buffer_size;
    U32             offset;

    struct list_head list;
};

struct st_thread_cache {
    U16             is_main_area;
#ifdef OBMP_DEBUG
    U16             is_used;
    pid_t           tid; /* For Debug */
#endif
    /* 1k -> 64k */
    mem_block_info_t *block_high[MMAP_THRES_HOLD >> SLICE_HIGH_SHIFT];
    /* 512bytes -> 1k */
    mem_block_info_t *block_mid[(SLICE_HIGH_THRES - SLICE_MID_THRES) >> SLICE_MID_SHIFT];
    /* 8 -> 512bytes */
    mem_block_info_t *block_low[SLICE_MID_THRES >> SLICE_LOW_SHIFT];
    struct list_head *chunk_list;
    pthread_mutex_t t_mutex;
};

struct st_mem_pool {
    U32             used_caches_cnt;
    U32             thread_cache_cnt;
    thread_cache_t  **thread_caches;
    pthread_mutex_t m_mutex;
};

#endif // endif _MP_TYPE_H_
